﻿using SqlServerMaintenanceSolution.Commands;
using SqlServerMaintenanceSolution.Models;
using SqlServerMaintenanceSolution.Views;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;

namespace SqlServerMaintenanceSolution.ViewModels
{
    public class LoginViewModel : ViewModelBase
    {
        /// <summary>
        /// The url to the help pagina on the MSDN web site.
        /// </summary>
        private const string HelpPagina = "https://msdn.microsoft.com/en-us/library/ms144284.aspx";

        private string _authentication;
        private NetworkProtocol networkProtocol;
        private bool optionsVisible;
        private SqlServerAuthentication sqlServerAuthentication;

        /// <summary>
        /// Initializes a new instance of the <see cref="LoginViewModel"/> class.
        /// </summary>
        public LoginViewModel()
        {
            this.NetworkProtocols = new ObservableCollection<NetworkProtocol>(NetworkProtocol.GetNetworkProtocols());
            this.SqlServerInstances = new ObservableCollection<SqlServerInstance>(SqlServerInstance.GetInstalledInstances());
            this.SqlServerAuthentications = new ObservableCollection<SqlServerAuthentication>(SqlServerAuthentication.GetServerAuthentications());
            InitializeCommands();

            if (this.SqlServerInstances.Any())
            {
                // Select the default instance or the first of the list if no instance flagged as default
                this.SqlServerInstance = this.SqlServerInstances.FirstOrDefault(x => x.isDefaultInstance());
                if (this.SqlServerInstance == null)
                {
                    this.SqlServerInstance = this.SqlServerInstances[0];
                }
            }

            if (this.SqlServerAuthentications.Any())
            {
                // Select the first by default
                this.SqlServerAuthentication = this.SqlServerAuthentications[0];
            }
        }

        /// <summary>
        /// Gets or sets the authentication.
        /// </summary>
        /// <value>
        /// The authentication.
        /// </value>
        public string Authentication
        {
            get { return _authentication; }
            set
            {
                if (_authentication == value) return;
                _authentication = value;

                this.SqlServerAuthentication = new SqlServerAuthentication(_authentication);

                OnPropertyChanged("SqlServerAuthentication");
                OnPropertyChanged("IntegratedSecurity");
            }
        }

        /// <summary>
        /// Gets the connect click command.
        /// </summary>
        /// <value>
        /// The connect click command.
        /// </value>
        public DelegateCommand ConnectClickCommand { get; private set; }

        /// <summary>
        /// Gets the exit command.
        /// </summary>
        /// <value>
        /// The exit command.
        /// </value>
        public ICommand ExitCommand { get; private set; }

        /// <summary>
        /// Gets the help click command.
        /// </summary>
        /// <value>
        /// The help click command.
        /// </value>
        public ICommand HelpClickCommand { get; private set; }

        /// <summary>
        /// Gets a value indicating whether this instance is integrated security.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is integrated security; otherwise, <c>false</c>.
        /// </value>
        public bool IsIntegratedSecurity
        {
            get
            {
                if (SqlServerAuthentication != null)
                    return !SqlServerAuthentication.IntegratedSecurity;
                else
                    return false;
            }
        }

        /// <summary>
        /// Gets or sets the network protocol.
        /// </summary>
        /// <value>
        /// The network protocol.
        /// </value>
        public NetworkProtocol NetworkProtocol
        {
            get { return this.networkProtocol; }
            set
            {
                if (value != NetworkProtocol)
                {
                    networkProtocol = value;
                    OnPropertyChanged("NetworkProtocol");
                }
            }
        }

        /// <summary>
        /// Gets the network protocols.
        /// </summary>
        /// <value>
        /// The network protocols.
        /// </value>
        public ObservableCollection<NetworkProtocol> NetworkProtocols { get; private set; }

        /// <summary>
        /// Gets the options command to open the Connection Properties Window
        /// </summary>
        /// <value>
        /// The options click command.
        /// </value>
        public ICommand OptionsClickCommand { get; private set; }

        /// <summary>
        /// Gets or sets a value indicating whether the options are visible.
        /// </summary>
        /// <value>
        ///   <c>true</c> if the options are visible; otherwise, <c>false</c>.
        /// </value>
        public bool OptionsVisible
        {
            get { return this.optionsVisible; }
            set
            {
                if (value != this.optionsVisible)
                {
                    this.optionsVisible = value;
                    OnPropertyChanged("OptionsVisible");
                }
            }
        }

        /// <summary>
        /// Gets or sets the password.
        /// </summary>
        /// <value>
        /// The password.
        /// </value>
        public string Password
        {
            get
            {
                if (SqlServerAuthentication != null)
                    return SqlServerAuthentication.Password;
                else
                    return "";
            }
            set
            {
                if (value != SqlServerAuthentication.Password)
                {
                    SqlServerAuthentication.Password = value;
                    OnPropertyChanged("Password");
                    this.ConnectClickCommand.RaiseCanExecuteChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the SQL server authentication.
        /// </summary>
        /// <value>
        /// The SQL server authentication.
        /// </value>
        public SqlServerAuthentication SqlServerAuthentication
        {
            get { return this.sqlServerAuthentication; }
            set
            {
                if (value != SqlServerAuthentication)
                {
                    this.sqlServerAuthentication = value;
                    OnPropertyChanged("SqlServerAuthentication");
                    OnPropertyChanged("IntegratedSecurity");
                    this.ConnectClickCommand.RaiseCanExecuteChanged();
                }
            }
        }

        /// <summary>
        /// Gets the SQL server authentications.
        /// </summary>
        /// <value>
        /// The SQL server authentications.
        /// </value>
        public ObservableCollection<SqlServerAuthentication> SqlServerAuthentications { get; private set; }

        /// <summary>
        /// Gets or sets the SQL server instance.
        /// </summary>
        /// <value>
        /// The SQL server instance.
        /// </value>
        public SqlServerInstance SqlServerInstance { get; set; }

        /// <summary>
        /// Gets the SQL server instances.
        /// </summary>
        /// <value>
        /// The SQL server instances.
        /// </value>
        public ObservableCollection<SqlServerInstance> SqlServerInstances { get; private set; }

        /// <summary>
        /// Gets or sets the user identifier.
        /// </summary>
        /// <value>
        /// The user identifier.
        /// </value>
        public string UserID
        {
            get
            {
                if (SqlServerAuthentication != null)
                    return SqlServerAuthentication.UserID;
                else
                    return "";
            }
            set
            {
                if (value != SqlServerAuthentication.UserID)
                {
                    SqlServerAuthentication.UserID = value;
                    OnPropertyChanged("UserID");
                    this.ConnectClickCommand.RaiseCanExecuteChanged();
                }
            }
        }

        /// <summary>
        /// Determines whether the connect command can be executed.
        /// </summary>
        /// <returns></returns>
        private bool CanClickConnect()
        {
            return SqlServerAuthentication != null
                && (SqlServerAuthentication.Authentication == Models.Enums.Authentication.WindowsAuthentication
                    || (SqlServerAuthentication.Authentication == Models.Enums.Authentication.SqlServerAuthentication
                       && !string.IsNullOrEmpty(SqlServerAuthentication.Password)
                       && !string.IsNullOrEmpty(SqlServerAuthentication.UserID)));
        }

        /// <summary>
        /// Initializes the commands.
        /// </summary>
        private void InitializeCommands()
        {
            ConnectClickCommand = new DelegateCommand(OnConnectClick, CanClickConnect);
            ExitCommand = new DelegateCommand(OnExit);
            HelpClickCommand = new DelegateCommand(OnHelpClick);
            OptionsClickCommand = new DelegateCommand(OnOptionsClick);
        }

        /// <summary>
        /// Called when the connect command is executed.
        /// </summary>
        private void OnConnectClick()
        {
            var mainScreen = new MainScreen()
            {
                DataContext = new MainScreenViewModel(SqlServerInstance, SqlServerAuthentication)
            };

            mainScreen.Show();
            this.OnExit();
        }

        /// <summary>
        /// Called when the exit command is executed.
        /// </summary>
        private void OnExit()
        {
            //Application.Current.Shutdown();
            Application.Current.Windows[0].Close();
        }

        /// <summary>
        /// Called when help command is executed.
        /// </summary>
        private void OnHelpClick()
        {
            System.Diagnostics.Process.Start(HelpPagina);
        }

        /// <summary>
        /// Called when options command is executed.
        /// </summary>
        private void OnOptionsClick()
        {
            this.OptionsVisible = !this.OptionsVisible;
        }
    }
}